/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package src.tarea1;

import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;

/**
 *
 * @author ginancm
 */
public class Transformaciones {
    
    private List <Double> datosGenerador;
    private List <Double> datosTransformados;
    
    public Transformaciones(List <Double> arrayDatos){
        datosGenerador=arrayDatos;
        datosTransformados=new ArrayList(arrayDatos.size());
    }
    
    public void transExponencial(double lambda){
        double tmp;
        double div=-1/lambda;
        for(int i=0; i<datosGenerador.size(); i++){
            tmp=datosGenerador.get(i);
            datosTransformados.add(div*Math.log(tmp));
        }
    }
    
    public void transNormalCentral(int n){
        List <Double> arrayDatos = new ArrayList<>(datosGenerador);
        double datoUniforme=0;
        double sumatoria;
        int idDato=0;
        while (!arrayDatos.isEmpty()) {
            
            boolean complete=true;
            sumatoria=0;
            /*Sumatoria
             */
            SUMATORIA:for (int i = 0; i < n; i++) {
                if(arrayDatos.isEmpty()){
                    complete=false;
                    break SUMATORIA;
                } else {
                    datoUniforme = arrayDatos.remove(0);
                    if(n!=12){
                        sumatoria+=datoUniforme;
                    }else{
                        sumatoria+=datoUniforme;
                    }
                }
            }
            
            if( n != 12 && complete ){
                sumatoria-=(double)n/2.0;
                sumatoria/=Math.sqrt((double)n/12.0);
            }else if( n == 12 && complete){
                sumatoria-=6.0;
            }
            
            /*Salvo datos
             */
            if(complete){
                if(idDato<datosTransformados.size()){
                    datosTransformados.set(idDato, sumatoria);
                }else{
                    datosTransformados.add(sumatoria);
                }
                idDato++;
            }
        }
    }
    
    public void transNormal(double media, double desvEstandar){
        int n=4;
        transNormalCentral(n);
        transNormal(n, media, desvEstandar);        
    }
    
    public void transNormal(int n, double media, double desvEstandar){
        transNormalCentral(n);
        int contador=0;
        double valAleat;
        for (Double datoAleat : datosTransformados) {
            valAleat= datoAleat * desvEstandar + media;
            datosTransformados.set(contador, valAleat);
            contador++;
        }
    }
    
    public void transPoisson(double lambda){
        int i, iMax, idDato;
        double constPoison=Math.pow(Math.E,-1.0*lambda);
        double probPoisson;
        double acumPoisson;
        idDato=0;
        iMax=0;
        for (Double datoUniforme : datosGenerador) {
            probPoisson = constPoison;
            acumPoisson = constPoison;
            i=0;
            while(datoUniforme>=acumPoisson){
                probPoisson*=(lambda/(i+1.0));
                acumPoisson+=probPoisson;
                i++;
            }
            if(i> iMax){
                iMax= i;
            }
            if(idDato<datosTransformados.size()){
                datosTransformados.set(idDato, (double)i);
            }else{
                datosTransformados.add((double)i);
            }
            idDato++;
        }
        /*Hago normalización de los datos
         */
//        normalizarDatosTransformados((double)iMax);
    }
    
    public void normalizarDatosTransformados(double iMax){
        int idDato=0;
        for (Double dato : datosTransformados) {
           datosTransformados.set(idDato, dato/iMax);
           idDato++;
        }
    }
    
    public void escribirSalida(String nombreArchivo){
        try {
              FileWriter outFile = new FileWriter(nombreArchivo);
              PrintWriter out = new PrintWriter(outFile);
                       
              // Write text to file
              for(int i=0; i<datosTransformados.size(); i++)
              {
                  out.printf("%.17f\n", datosTransformados.get(i));
                          
              }
              
              out.close();
          } catch (IOException e){
              e.printStackTrace();
         }
    }
    public void escribirDatosNormales(String nombreArchivo){
        try {
              FileWriter outFile = new FileWriter(nombreArchivo);
              PrintWriter out = new PrintWriter(outFile);
                       
              // Write text to file
              for(int i=0; i<datosGenerador.size(); i++)
              {
                  out.printf("%.17f\n", datosGenerador.get(i));
                          
              }
              
              out.close();
          } catch (IOException e){
              e.printStackTrace();
         }
    }
    /*Transformación binomial según yo
     */
    public void transBinomialAlt(int intentos, double prob){
        List <Double> listaUniforme= new ArrayList(datosGenerador);
        double datoUniforme = 0.0;
        boolean pude=true;
        int contador, idDato;
        
        idDato=0;
        while(!listaUniforme.isEmpty()){
            contador=0;
            CONTEO:for(int i=0;i<intentos;i++){
                if(!listaUniforme.isEmpty()){
                    datoUniforme = listaUniforme.remove(0);
                    if(datoUniforme<prob){
                        contador++;
                    }
                }else{
                    pude=false;
                    break CONTEO;
                }
            }
            if(pude){
                if(idDato<datosTransformados.size()){
                    datosTransformados.set(idDato, (double)contador);
                }else{
                    datosTransformados.add((double)contador);
                }
                idDato++;
            }
        }
    }
    
    public void transBinomial(int intentos, double probabilidad)
    {
        double [] probabilidades=new double[intentos];
        List <Clase> acumuladas= new ArrayList(intentos);
        
        //Determinar probabilidades segun la distribucion
        
        double complemento=1-probabilidad;
        double exp;
        
        for(int i=0; i<intentos; i++)
        {
            exp=intentos-i;
            probabilidades[i]=combinatoria(intentos,i)*Math.pow(probabilidad,i)*Math.pow(complemento,exp);
        }
        
        //Calcular probabilidades acumuladas
        
        double infTmp, supTmp;
        infTmp=0.0;
      
        for (int i=0; i<intentos; i++)
        {
            supTmp=probabilidades[i]+infTmp;
            acumuladas.add(new Clase(infTmp,supTmp));
            infTmp=supTmp;  
        }
        
        //Transformacion de datos
         Clase claseTmp=acumuladas.get(0);
            int numInt=0;
        
        for(int i=0; i<datosGenerador.size(); i++)
        {
		while (!claseTmp.pertenece(datosGenerador.get(i)))
		{
			numInt++;
			claseTmp=acumuladas.get(numInt);
		}
                
                datosTransformados.add((double)numInt);
        }
        
    }
    
    private int combinatoria(int n, int r)
    {
        //n!/r!*(n-r)!
        int resultado;
        BigInteger fact1=factorial(n);
        BigInteger fact2=factorial(n-r);
        BigInteger fact3=factorial(r);
        
        resultado = fact1.divide(fact2.multiply(fact3)).intValue();
        
        return resultado;
        
    }
    
    private BigInteger factorial (int n)
    {
        BigInteger resultado=BigInteger.ONE;
        
        for(int n_esimo=n;n_esimo>1;n_esimo--)
        {
            resultado=resultado.multiply(BigInteger.valueOf(n_esimo));
        }
        return resultado;
    }
    
    
}
